﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Xml;

namespace OfficeOpenXml
{
    public class CellBorder
    {
        private readonly ExcelWorksheet worksheet;
        private ExcelCell cell;

        public CellBorder(ExcelWorksheet worksheet, ExcelCell cell)
        {
            this.worksheet = worksheet;
            this.cell = cell;        
            this.left = new Border(this, BorderType.Left);
            this.right = new Border(this, BorderType.Right);
            this.top = new Border(this, BorderType.Top);
            this.bottom = new Border(this, BorderType.Bottom);
            this.diagonal = new Border(this, BorderType.Diagonal);
        }
        
        private Border left;
        public Border Left
        {
            get { return this.left; }
        }

        public int BorderID
        {
            get
            {
                return cell.BorderID;
            }
        }
        
        internal XmlElement GetBorderElement()
        {
            return (XmlElement) this.worksheet.GetBorderElement(this.BorderID);
        }

        private Border right;
        public Border Right
        {
            get { return this.right; }
        }

        private Border top;
        public Border Top
        {
            get { return this.top; }
        }

        private Border bottom;
        public Border Bottom
        {
            get { return this.bottom; }
        }

        private Border diagonal;
        public Border Diagonal
        {
            get { return this.diagonal; }
        }

        internal XmlNamespaceManager NameSpaceManager
        {
            get
            {
                return this.worksheet.NameSpaceManager;
            }
        }

        public bool DiagonalUp
        {
            get
            {
                XmlElement element = this.GetBorderElement();
                bool result = false;
                string attribute = element.GetAttribute("diagonalUp");
                if (!string.IsNullOrEmpty(attribute))
                {
                    result = int.Parse(attribute) == 1;
                }
                return result;
            }
            set
            {
                XmlElement element = this.BorderID == 0 ? this.CreateBorder() : this.GetBorderElement();
                element.SetAttribute("diagonalUp", value ? "1" : "0");
            }
        }

        public bool DiagonalDown
        {
            get
            {
                XmlElement element = this.GetBorderElement();
                bool result = false;
                string attribute = element.GetAttribute("diagonalDown");
                if (!string.IsNullOrEmpty(attribute))
                {
                    result = int.Parse(attribute) == 1;
                }
                return result;
            }
            set
            {
                XmlElement element = this.BorderID == 0 ? this.CreateBorder() : this.GetBorderElement();
                element.SetAttribute("diagonalDown", value ? "1" : "0");
            }
        }

        internal XmlElement CreateBorder()
        {
            XmlElement currentBorder = this.GetBorderElement();
            XmlElement newBorder = this.worksheet.xlPackage.Workbook.StylesXml.CreateElement("border", ExcelPackage.schemaMain);

            foreach (XmlAttribute attribute in currentBorder.Attributes)
            {
                newBorder.SetAttribute(attribute.Name, attribute.Value);
            }

            int index = this.worksheet.AddBorder(newBorder);
            
            this.cell.BorderID = index;

            GetChild(BorderType.Left, true);
            GetChild(BorderType.Right, true);
            GetChild(BorderType.Top, true);
            GetChild(BorderType.Bottom, true);
            GetChild(BorderType.Diagonal, true);

            return newBorder;
        }

        internal XmlElement GetChild(BorderType type)
        {
            return GetChild(type, false);
        }
        
        internal XmlElement GetChild(BorderType type, bool forWriting)
        {
            string name = string.Format("./d:{0}", type.ToString().ToLower());
            XmlElement element;
            if (forWriting && this.BorderID == 0)
            {
                element = this.CreateBorder();
            }
            else
            {
                element = this.GetBorderElement();
            }
            XmlElement child = null;
            if (element != null)
            {
                child = (XmlElement) element.SelectSingleNode(name, this.worksheet.NameSpaceManager);
                if (forWriting && child == null)
                {
                    string elementName = name.Substring(name.IndexOf(':') + 1);
                    child = this.worksheet.xlPackage.Workbook.StylesXml.CreateElement(elementName, ExcelPackage.schemaMain);
                    element.AppendChild(child);
                    
                    var color = this.worksheet.xlPackage.Workbook.StylesXml.CreateElement("color", ExcelPackage.schemaMain);
                    //color.SetAttribute("indexed", "64");
                    child.AppendChild(color);
                }
            }
            return child;
        }
    }

    public class Border
    {
        private readonly CellBorder border;
        private readonly BorderType type;

        public Border(CellBorder border, BorderType type)
        {
            this.type = type;
            this.border = border;
        }

        private XmlElement GetElement()
        {
            return GetElement(false);
        }

        XmlElement GetElement(bool forWriting)
        {            
            XmlElement element = this.border.GetChild(type, forWriting);          
            return element;
        }

        public BorderStyle Style
        {
            get
            {
                BorderStyle style = BorderStyle.None;
                XmlElement bd = this.GetElement();
                if (bd != null)
                {
                    string styleString = bd.GetAttribute("style");
                    if (!string.IsNullOrEmpty(styleString))
                    {
                        style = (BorderStyle) Enum.Parse(typeof (BorderStyle), styleString, true);
                    }
                }
                return style;
            }
            set
            {               
                XmlElement bd = GetElement(true);
                bd.SetAttribute("style", value.ToString().ToLower());
                bd.SetAttribute("style", value.ToString().ToLower());
            }
        }

        
        public Color Color
        {
            get
            {
                Color color = Color.Transparent;
                XmlElement element = this.GetElement();
                if (element != null)
                {
                    XmlElement colorElement = (XmlElement) element.SelectSingleNode("./d:color", this.border.NameSpaceManager);
                    if (colorElement != null)
                    {
                        string rgbString = colorElement.GetAttribute("rgb");
                        int rgb = Convert.ToInt32(rgbString, 16);
                        Color.FromArgb(rgb);
                    }
                }


                return color;
            }
            set
            {
                XmlElement element = this.GetElement(true);
                XmlElement colorElement = (XmlElement) element.SelectSingleNode("./d:color", this.border.NameSpaceManager);
                int rgb = value.ToArgb();
                string rgbString = rgb.ToString("X2");
                colorElement.SetAttribute("rgb", rgbString);
            }
        }
    }

    public enum BorderStyle
    {
        None,               
        DashDot,
        DashDotDot,
        Dashed,
        Dotted,
        Double,
        Hair,
        Medium,
        MediumDashDot,
        MediumDashDotDot,
        MediumDashed,
        SlantDashDot,
        Thick,
        Thin,
    }

    public enum BorderType
    {
        Left,
        Right,
        Top,
        Bottom,
        Diagonal
    }
}
